package test

import (
	"context"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// 查询全部
func FindAll(mongo *mongo.Database, ctx context.Context) error {
	cur, err := mongo.Collection("test").Find(ctx, bson.M{}) // 查询所有就是bson.M{}，没有任何条件

	// 遍历数据
	for cur.TryNext(ctx) {
		result, _ := cur.Current.Elements()
		fmt.Println(result)
	}
	return err
}

// 单独查询，并且解析成对应的结构体
func FindAdd(mongo *mongo.Database, ctx context.Context) {

	// 查询Add3
	result3 := Add3{}
	findFilter3 := bson.M{"id": 3}
	mongo.Collection("test").FindOne(ctx, findFilter3).Decode(&result3)
	fmt.Println("add3:", result3)
}

// 查询某个具体的字段
func FindField(mongo *mongo.Database, ctx context.Context) {

	// 下面的查询相当于 SELECT add1list from test WHERE id = 3
	projection1 := bson.D{{"add1list", 1}, {"_id", 0}} // 查询指定字段add1List，排除字段“_id”.1表示选择，设置为0表示排除
	findFilter1 := bson.M{"id": 3}                     // 查询条件
	temp1 := mongo.Collection("test").FindOne(ctx, findFilter1, options.FindOne().SetProjection(projection1))
	rawByte, _ := temp1.DecodeBytes()
	rawS := rawByte.String()
	fmt.Println("rawS:", rawS)

	add3 := Add3{}
	temp1.Decode(&add3) // 解析
	fmt.Println("add3:", add3)

	// 下面的查询仅返回数组里的text字段
	projection2 := bson.D{{"add1list.text", 1}, {"_id", 0}} // 查询指定字段add1List，排除字段“_id”.1表示选择，设置为0表示排除
	// projection2 := bson.M{"add1list.text": 1, "_id": 0}            // 这种方式也行
	// projection2 := bson.M{"add1list": bson.M{"text": 1}, "_id": 0} // 这种方式也行
	findFilter2 := bson.M{"id": 3} // 查询条件
	temp2 := mongo.Collection("test").FindOne(ctx, findFilter2, options.FindOne().SetProjection(projection2))

	rawByte, _ = temp2.DecodeBytes()
	rawV, _ := rawByte.Values()
	fmt.Println("rawV:", rawV[0])

	add3_1 := Add3{}
	temp2.Decode(&add3_1) // 解析
	fmt.Println("add3_1:", add3_1)

	// 下面查询数组中完全匹配的文档
	projection3 := bson.M{"add1list": 1, "_id": 0}                       // 查询指定字段add1List，排除字段“_id” 1表示选择，设置为0表示排除
	findFilter3 := bson.M{"add1list": bson.M{"id": 4, "text": "hello4"}} // 此处的查询条件需要完全匹配才行
	temp3 := mongo.Collection("test").FindOne(ctx, findFilter3, options.FindOne().SetProjection(projection3))

	add3_2 := Add3{}
	temp3.Decode(&add3_2) // 解析
	fmt.Println("add3_2:", add3_2)

	// 下面查询数组中满足一定条件的文档
	projection4 := bson.M{"add1list": 1, "_id": 0}   // 查询指定字段add1List，排除字段“_id” 1表示选择，设置为0表示排除
	findFilter4 := bson.M{"add1list.text": "hello5"} // 此处查询text等于hello5的文档
	temp4 := mongo.Collection("test").FindOne(ctx, findFilter4, options.FindOne().SetProjection(projection4))

	add3_3 := Add3{}
	temp4.Decode(&add3_3) // 解析
	fmt.Println("add3_3:", add3_3)
}

// 其他条件查询，见：https://www.mongodb.com/docs/manual/reference/operator/query/
func Find(mongo *mongo.Database, ctx context.Context) {
	// 下面的查询相当于 SELECT id from test WHERE id > 2
	projection := bson.M{"_id": 0}
	findFilter1 := bson.M{"id": bson.M{"$gt": 2}} // 查询条件 gt是大于，gte是大于等于
	temp1, _ := mongo.Collection("test").Find(ctx, findFilter1, options.Find().SetProjection(projection))
	// 遍历数据
	for temp1.TryNext(ctx) {
		result := temp1.Current.Lookup("id")
		fmt.Println(result)
	}
	fmt.Println("1~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 下面的查询相当于 SELECT id from test WHERE id <= 3
	findFilter2 := bson.M{"id": bson.M{"$lte": 3}} // 查询条件 lt是小于，lte是小于等于
	temp2, _ := mongo.Collection("test").Find(ctx, findFilter2, options.Find().SetProjection(projection))
	// 遍历数据
	for temp2.TryNext(ctx) {
		result := temp2.Current.Index(0)
		fmt.Println(result)
	}
	fmt.Println("2~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 查询不包含add1list字段的文档
	findFilter3 := bson.M{"add1list": nil} // 查询条件
	temp3, _ := mongo.Collection("test").Find(ctx, findFilter3, options.Find().SetProjection(projection))
	// 遍历数据
	for temp3.TryNext(ctx) {
		result := temp3.Current.String()
		fmt.Println(result)
	}
	fmt.Println("3~~~~~~~~~~~~~~~~~~~~~~~~~~")

	// 查询存在add1list字段的文档
	findFilter4 := bson.M{"add1list": bson.M{"$exists": true}} // 查询条件
	temp4, _ := mongo.Collection("test").Find(ctx, findFilter4, options.Find().SetProjection(projection))
	// 遍历数据
	for temp4.TryNext(ctx) {
		result := temp4.Current.String()
		fmt.Println(result)
	}
	fmt.Println("4~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 查询add1list是array类型的文档，类型见：https://www.mongodb.com/docs/manual/reference/bson-types/
	findFilter5 := bson.M{"add1list": bson.M{"$type": 4}} // 类别编号，4表示array
	temp5, _ := mongo.Collection("test").Find(ctx, findFilter5, options.Find().SetProjection(projection))
	// 遍历数据
	for temp5.TryNext(ctx) {
		result := temp5.Current.String()
		fmt.Println(result)
	}
	fmt.Println("5~~~~~~~~~~~~~~~~~~~~~~~~~~")

	// 查询add1list长度为3的文档
	findFilter6 := bson.M{"add1list": bson.M{"$size": 3}} // 类别编号，4表示array
	temp6, _ := mongo.Collection("test").Find(ctx, findFilter6, options.Find().SetProjection(projection))
	// 遍历数据
	for temp6.TryNext(ctx) {
		result := temp6.Current.String()
		fmt.Println(result)
	}
	fmt.Println("6~~~~~~~~~~~~~~~~~~~~~~~~~~")

	// 指定多个条件查询,$elemMatch仅数组类型可用，以下查询add1list中有某个元素的id同时满足大于4且小于5，显然没有这样的元素
	findFilter7 := bson.M{"add1list": bson.M{"$elemMatch": bson.M{"id": bson.M{"$gt": 4, "$lt": 5}}}}
	temp7, _ := mongo.Collection("test").Find(ctx, findFilter7, options.Find().SetProjection(projection))
	// 遍历数据
	for temp7.TryNext(ctx) {
		result := temp7.Current.String()
		fmt.Println(result)
	}
	fmt.Println("7~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 和上面形成对比，下面的查询是add1list中存在元素的id大于4，且存在元素的id小于5.可以不是同一个元素，和上面对比，区别就是上面必须是同一个元素满足所有条件
	findFilter8 := bson.M{"add1list.id": bson.M{"$gt": 4, "$lt": 5}}
	temp8, _ := mongo.Collection("test").Find(ctx, findFilter8, options.Find().SetProjection(projection))
	// 遍历数据
	for temp8.TryNext(ctx) {
		result := temp8.Current.String()
		fmt.Println(result)
	}
	fmt.Println("8~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 查询数组中包含的id的文档
	findFilter9 := bson.M{"add1list.id": bson.M{"$in": bson.A{4}}}
	temp9, _ := mongo.Collection("test").Find(ctx, findFilter9, options.Find().SetProjection(projection))
	// 遍历数据
	for temp9.TryNext(ctx) {
		result := temp9.Current.String()
		fmt.Println(result)
	}
	fmt.Println("9~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 正则匹配:"$options": "i"表示不区分大小写。"$nin": bson.A{"hello5"}表示text不能等于数组里的值，详见：https://www.mongodb.com/docs/manual/reference/operator/query/regex/
	findFilter10 := bson.M{"add1list.text": bson.M{"$regex": "Hello*", "$options": "i", "$nin": bson.A{"hello5"}}}
	temp10, _ := mongo.Collection("test").Find(ctx, findFilter10, options.Find().SetProjection(projection))

	// 遍历数据
	for temp10.TryNext(ctx) {
		result := temp10.Current.String()
		fmt.Println(result)
	}
	fmt.Println("10~~~~~~~~~~~~~~~~~~~~~~~~~~")

}
